import string
import tempfile
import os
import re
import Image
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template.context import RequestContext
from django.db.models.fields.related import ManyToManyRel
from django.contrib.gis.gdal.geometries import MultiPoint
try:
    from django.contrib.gis.geos.geometry import Point
except:
    from django.contrib.gis.geos.geometries import Point
from django.core.urlresolvers import reverse
from django.conf import settings

from webmapper.models import Route, Area, Photo, PointOfInterest, MapLayer, StaticMapLayer, MapKey, Map
from webmapper.load import Gpx
from webmapper import forms
from webmapper.settings import (WEBMAPPER_MEDIA_URL,
                                WEBMAPPER_IMG_URL,
                                WEBMAPPER_CSS_URL,
                                WEBMAPPER_JS_URL,)

class Bounds:
    x1 = 0.0
    y1 = 0.0
    x2 = 0.0
    y2 = 0.0

class layer:
    @staticmethod
    @login_required
    def uploadKml(request):
        if request.method == "POST":
            f = forms.KmlLayerUploadForm(request.POST, request.FILES)
            if f.is_valid():
                newLayer = f.save(commit=False)
                newLayer.created_by = request.user
                #TODO: Validate the KML FILE
                newLayer.save();
                f.save_m2m();
                return HttpResponseRedirect(reverse('dashboard'))
        else:
            f = forms.KmlLayerUploadForm()
        return render_to_response('webmapper/genericform.html', {
            'form': f,
            'action': 'Create',
            'what': 'Layer',
            'actionurl': reverse('layer-kml-upload'),
        })
        
    @staticmethod
    @login_required
    def edit(request, id):
        layer = get_object_or_404(StaticMapLayer, pk=id)
        if request.method == "POST":
            f = forms.KmlLayerUploadForm(request.POST, instance=layer)
            if f.is_valid():
                f.save();
                return HttpResponseRedirect(reverse('dashboard'))
        else:
            f = forms.KmlLayerUploadForm(instance=layer)
        return render_to_response('webmapper/genericform.html', {
            'form': f,
            'action': 'Modify',
            'what': 'Layer',
            'actionurl': reverse('layer-edit', args=[id]),            
        })

class map:
    @staticmethod
    @login_required
    def create(request):
        if request.method == "POST":
            f = forms.MapForm(request.POST)
            if f.is_valid():
                newMap = f.save(commit=False)
                newMap.created_by = request.user
                newMap.save();
                f.save_m2m();
                return HttpResponseRedirect(reverse('dashboard'))
        else:
            f = forms.MapForm()
        return render_to_response('webmapper/genericform.html', {
            'form' : f,
            'action': 'Create',
            'what': 'Map',
            'actionurl': reverse('map-create'),
        })
    
    @staticmethod
    @login_required
    def edit(request, id):
        theMap = get_object_or_404(Map, pk=id)
        if request.method == "POST":
            f = forms.MapForm(request.POST, instance=theMap)
            if f.is_valid():
                f.save();
                return HttpResponseRedirect(reverse('dashboard'))
        else:
            f = forms.MapForm(instance=theMap)
        return render_to_response('webmapper/genericform.html', {
            'form': f,
            'action': 'Modify',
            'what': 'Map',
            'actionurl': reverse('map-edit', args=[id]),            
        })
    
    @staticmethod
    def viewSnap(request, uniqueName):
        mymap = get_object_or_404(Map, unique_name=uniqueName)
        static_layer_list = mymap.static_layers.all().order_by('unique_name')
        dynamic_layer_list = mymap.dynamic_layers.all().order_by('unique_name')
        map_height = request.GET.get('height', '300')
        showkey = request.GET.get('key', '1') != '0'
        showcaption = request.GET.get('caption', '1') != '0'
        key_list = []
        if showkey:
            for layer in static_layer_list:
                key_list.extend(layer.map_keys.all())
        return render_to_response(
            'webmapper/maps/mapsnap_google.html',   # _openlayers isn't quite working yet...
            {
                'map': mymap,
                'GOOGLE_API_KEY': settings.GOOGLE_API_KEY,
                'SITE_URL' : settings.SITE_URL,
                'WEBMAPPER_CSS_URL': WEBMAPPER_CSS_URL,
                'WEBMAPPER_IMG_URL': WEBMAPPER_IMG_URL,
                'WEBMAPPER_JS_URL': WEBMAPPER_JS_URL,
                'map_center_lat': mymap.center.y,
                'map_center_lon': mymap.center.x,
                'static_layer_list': static_layer_list,
                'dynamic_layer_list': dynamic_layer_list,
                'key_list': key_list,
                'showkey': showkey,
                'showcaption': showcaption,
                'map_height': map_height,
            },
            context_instance=RequestContext(request))
    
    @staticmethod
    def viewOverview(request, uniqueName):
        mymap = get_object_or_404(Map, unique_name=uniqueName)
        static_layer_list = mymap.static_layers.all().order_by('unique_name')
        dynamic_layer_list = mymap.dynamic_layers.all().order_by('unique_name')
        key_list = []
        for layer in static_layer_list:
            key_list.extend(layer.map_keys.all())
        return render_to_response(
            'webmapper/maps/map_google_dynamic.html',
            {
                'map': mymap,
                'GOOGLE_API_KEY': settings.GOOGLE_API_KEY,
                'SITE_URL' : settings.SITE_URL,
                'WEBMAPPER_CSS_URL': WEBMAPPER_CSS_URL,
                'WEBMAPPER_IMG_URL': WEBMAPPER_IMG_URL,
                'WEBMAPPER_JS_URL': WEBMAPPER_JS_URL,
                'map_center_lat': mymap.center.y,
                'map_center_lon': mymap.center.x,
                'static_layer_list': static_layer_list,
                'dynamic_layer_list': dynamic_layer_list,
                'key_list': key_list,
            },
            context_instance=RequestContext(request))

    @staticmethod
    def viewInfo(request, uniqueName):
        mymap = get_object_or_404(Map, unique_name=uniqueName)
        return render_to_response(
            'webmapper/maps/overview.html',
            {
                'map': mymap,
                'WEBMAPPER_CSS_URL': WEBMAPPER_CSS_URL,
            },
            context_instance=RequestContext(request))


class mapKey:
    @staticmethod
    @login_required
    def create(request):
        if request.method == "POST":
            f = forms.MapKeyForm(request.POST, request.FILES)
            if f.is_valid():
                newMapKey = f.save(commit=False)
                newMapKey.save();
                f.save_m2m();
                graphic = Image.open(newMapKey.graphic.path)
                graphic.thumbnail([42, 42], Image.ANTIALIAS)
                graphic.save(newMapKey.graphic.path)

                return HttpResponseRedirect(reverse('dashboard'))
        else:
            f = forms.MapKeyForm()
        return render_to_response('webmapper/genericform.html', {
            'form': f,
            'action': 'Create',
            'what': 'MapKey',
            'actionurl': reverse('mapkey-create'),
        })
        
    @staticmethod
    @login_required
    def edit(request, id):
        mapkey = get_object_or_404(MapKey, pk=id)
        if request.method == "POST":
            f = forms.MapKeyForm(request.POST, request.FILES, instance=mapkey)
            if f.is_valid():
                f.save();
                if 'graphic' in request.FILES:
                    graphic = Image.open(mapkey.graphic.path)
                    graphic.thumbnail([42, 42], Image.ANTIALIAS)
                    graphic.save(mapkey.graphic.path)
                return HttpResponseRedirect(reverse('dashboard'))
        else:
            f = forms.MapKeyForm(instance=mapkey)
        return render_to_response('webmapper/genericform.html', {
            'form': f,
            'action': 'Modify',
            'what': 'MapKey',
            'actionurl': reverse('mapkey-edit', args=[id]),            
        })
        

class Kml:
    @staticmethod
    def mapLayer(request, uniqueName):
        '''View a MapLayer object as KML'''
        dynlayer = get_object_or_404(MapLayer, unique_name=uniqueName)
        kml = '<?xml version="1.0" encoding="UTF-8"?>\n <kml xmlns="http://www.opengis.net/kml/2.2">\n'
        for obj in dynlayer.pointofinterest_set.all():
            kml += Kml.placemarkTag(obj)
        kml += '</kml>\n'
        return HttpResponse(kml, 'application/vnd.google-earth.kml+xml')

    @staticmethod
    def mapObject(request, id, map_object):
        '''View a MapObject as KML'''
        obj = get_object_or_404(map_object, pk=id)
        kml = (
            '<?xml version="1.0" encoding="UTF-8"?>\n'
            '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
            '%s\n'
            '</kml>\n'
            ) %(Kml.placemarkTag(obj))
        return HttpResponse(kml, 'application/vnd.google-earth.kml+xml')
    
    @staticmethod
    def placemarkTag(obj):
        '''Given a MapObject, create the placemark KML tag'''
        kml = (
            '<Placemark id="%s">\n'
            '<name>%s</name>\n'
            '<description><![CDATA[<p>%s</p>]]></description>\n'
            '%s\n'
            '</Placemark>\n'
            ) %(obj.title, obj.title, obj.caption, obj.getGeometry().kml)
        return kml


@login_required
def uploadRoute(request):
    if request.method == "POST":
        f = forms.RouteUploadForm(request.POST)
        if f.is_valid():
            newRoute = f.save(commit=False)
            newRoute.created_by = request.user
            if 'gpx' in request.FILES:
                gpxFile = request.FILES['gpx']
                # Save the gpx as a temp file...
                targetPath = tempfile.mkstemp()[1]
                destination = open(targetPath, 'wt')
                for chunk in gpxFile.chunks():
                    destination.write(chunk)
                destination.close()
            newRoute.track = Gpx.CreateMultiLineString(targetPath, newRoute)
            #Delete the tempfile
            os.remove(targetPath)
            newRoute.save();
            f.save_m2m();
            #Redirect to the routes view.
            return HttpResponseRedirect(reverse('home-view')) # Or Success! Page.
    else:
        f = forms.RouteUploadForm() # Create an unbounded form - for a GET request.
    return render_to_response('webmapper/routeupload.html', {
        'form': f,
    })


def homeView(request):
    map_list = Map.objects.all().order_by("unique_name")
    return render_to_response('webmapper/home.html', {
        'map_list': map_list
        }, context_instance=RequestContext(request))

@login_required
def dashboard(request):
    layer_list = StaticMapLayer.objects.all().order_by("unique_name")
    key_list = MapKey.objects.all().order_by("unique_name")
    map_list = Map.objects.all().order_by("unique_name")
    return render_to_response('webmapper/dashboard.html', {
        'layer_list': layer_list,
        'key_list': key_list,
        'map_list': map_list
        }, context_instance=RequestContext(request))




def growBounds(bounds, geom):
    """ Takes a point or a envelope (polygon square) """
    if isinstance(geom, Point):
        if bounds.x1 < geom.x:
            bounds.x1 = geom.x
        if bounds.y1 < geom.y:
            bounds.y1 = geom.y
        if bounds.x2 > geom.x:
            bounds.x2 = geom.x
        if bounds.y2 > geom.y:
            bounds.y2 = geom.y
    else:
        if bounds.x1 < geom[0][0][0]:
            bounds.x1 = geom[0][0][0]
        if bounds.y1 < geom[0][0][1]:
            bounds.y1 = geom[0][0][1]
        if bounds.x2 > geom[0][2][0]:
            bounds.x2 = geom[0][2][0]
        if bounds.y2 > geom[0][2][1]:
            bounds.y2 = geom[0][2][1]
    return bounds

def getBounds(geom):
    """ Takes a point or a envelope (polygon square) """
    bounds = Bounds()
    if isinstance(geom, Point):
        bounds.x1 = bounds.x2 = geom.x
        bounds.y1 = bounds.y2 = geom.y
    else:
        bounds.x1 = geom[0][0][0]
        bounds.y1 = geom[0][0][1]
        bounds.x2 = geom[0][2][0]
        bounds.y2 = geom[0][2][1]
    return bounds

@login_required
def mapPage(request, id, map_object):
    """ View an OpenLayers map with KML overlays """
    obj = get_object_or_404(map_object, pk=id)
    if isinstance(obj, Route):
        map_url = reverse('route-map-embed', args=[id])
    if isinstance(obj, Area):
        map_url = reverse('area-map-embed', args=[id])
    if isinstance(obj, Photo):
        map_url = reverse('photo-map-embed', args=[id])
    if isinstance(obj, PointOfInterest):
        map_url = reverse('poi-map-embed', args=[id])
    return render_to_response('webmapper/maps/kmlmap.html', {'map_url':map_url}, context_instance=RequestContext(request))


@login_required
def embedKmlMap(request, id, map_object):
    """ Create an embeddable map as an HTML page """
    obj = get_object_or_404(map_object, pk=id)
    bounds = Bounds()
    bounds_set = False
    route_list = []
    area_list = []
    photo_list = []
    poi_list = []
    #if isinstance(obj, MapTag):
    #    route_list = obj.route_set.all()
    #    area_list = obj.area_set.all()
    #    photo_list = obj.photo_set.all()
    #    poi_list = obj.pointofinterest_set.all()
    if isinstance(obj, Route):
        route_list.append(obj) # Just show a single Route
    if isinstance(obj, Area):
        area_list.append(obj) # Just show a single area
    if isinstance(obj, Photo):
        photo_list.append(obj) # Just show a single photo
    if isinstance(obj, PointOfInterest):
        poi_list.append(obj) # Just show a single point of interest
        
    # Set the bounds...
    for ar in area_list:
        if bounds_set:
            bounds = growBounds(bounds, ar.mpoly.envelope)
        else:
            bounds_set = True
            bounds = getBounds(ar.mpoly.envelope)
    for rt in route_list:
        if bounds_set:
            bounds = growBounds(bounds, rt.track.envelope)
        else:
            bounds_set = True
            bounds = getBounds(rt.track.envelope)
    for p in photo_list:
        if bounds_set:
            bounds = growBounds(bounds, p.location)
        else:
            bounds_set = True
            bounds = getBounds(p.location)
    for p in poi_list:
        if bounds_set:
            bounds = growBounds(bounds, p.loc)
        else:
            bounds_set = True
            bounds = getBounds(p.loc)
    return render_to_response(
        'webmapper/maps/embedkmlmap.html',
        {
            'bounds': bounds,
            'route_list': route_list,
            'area_list': area_list,
            'photo_list': photo_list,
            'poi_list': poi_list,
            'GOOGLE_API_KEY': settings.GOOGLE_API_KEY
        }, context_instance=RequestContext(request))

@login_required
def mapEmbedded(request, uniqueName):
    html = "<html><body>Coming soon. Unique name = %s</body></html>" % uniqueName
    return HttpResponse(html)
